/**
 * @file Text.c
 * @brief Routines for manipulating text windows
 * @author Matt Stallmann @date 29 Dec 2001
 * $Id: Text.c 10 2007-06-28 20:08:57Z mfms $
 */

/*
 *  Copyright (C) 2001  Matthias Stallmann.
 *  Contact: matt_stallmann@ncsu.edu
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program (file COPYING.txt); if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 *  USA.
 */

#include "All.h"
#include "Text.h"

/*------------------------------------------------------------
	Pops up a window with a message.
	OUTPUT : Returns an id for the message window.
	FUNCTIONS CALLED : write_text_window().
	------------------------------------------------------------*/
TWIN create_text_window(int xp, int yp, char *mesg_str)
{
  Window	twin;
  TWIN retval;
  unsigned long		valuemask;
  XSetWindowAttributes	attr_str;

  twin = XCreateSimpleWindow(disp, main_canvas, xp, yp,
									  MSG_HPAD * 2, MSG_VPAD * 2, MSG_BORDER_WIDTH,
									  black, white);
  attr_str.bit_gravity = NorthWestGravity;
  valuemask = CWBitGravity;
  XChangeWindowAttributes(disp, twin, valuemask, &attr_str);
  XSelectInput(disp, twin, ExposureMask);
  retval = TWL_add(twin);
  write_text_window(retval, mesg_str);
  return(retval);
} /* create_text_window ends */

TWIN find_text_window(Window xwin)
{
  return TWL_lookup(xwin);
}

void write_text_window(TWIN wind, char *mesg_str)
     /* write the text 'mesg_str' into the window 'wind' and resize the
        window appropriately ('mesg_str' may contain '\n's);
        as a side effect, 'mesg_str' is stored as the message associated
        with wind in the text window list */
     /* 6/3/96 - bug fix: added save_str so that temp_str can be freed
        correctly */
{
  unsigned int   number_of_lines; /* number of lines in the message */
  unsigned int   max_line_width; /* maximum width of a line (in pixels) */
  unsigned int   current_line_length; /* length of current line */
  char*          beginning_of_line; /* pointer to beginning of current
													line */
  char*          temp_str;	/* used to store string, since
										XDrawString will insert nulls */
  char*		 save_str;	/* save pointer to temp_str so that it
									can be freed */

  /* store message in text window list */
  TWL_change(wind, mesg_str);

  /* create temporary string and store message in it */
  save_str = temp_str = malloc(1 + strlen(mesg_str));
  strcpy(temp_str, mesg_str);

  /* calculate number of lines and max line length */
  number_of_lines = 0;
  max_line_width = 0;
  beginning_of_line = temp_str;
  current_line_length = 0;
  while (*temp_str) {
    /* INVARIANT: number_of_lines == number of '\n' so far
		 max_line_width == maximum width of a string between
		 2 consecutive '\n'
		 beginning_of_line == pointer to character after most
		 recent '\n'
		 current_line_length == number of characters since most
		 recent '\n' */
    if (*temp_str == '\n') {
      extern XFontStruct* msg_font_struct;
      unsigned int        current_line_width;

      number_of_lines++;
      current_line_width = XTextWidth(msg_font_struct, beginning_of_line,
												  current_line_length);
      if (current_line_width > max_line_width)
		  max_line_width = current_line_width;
      beginning_of_line = temp_str + 1;
      current_line_length = 0;
    }
    else current_line_length++;
    temp_str++;
  }

  if (current_line_length > 0) { /* unfinished line */
    extern XFontStruct* msg_font_struct;
    unsigned int        current_line_width;

    number_of_lines++;
    current_line_width = XTextWidth(msg_font_struct, beginning_of_line,
												current_line_length);
    if (current_line_width > max_line_width)
      max_line_width = current_line_width;
  }

  /* resize window based on string */
  {
    extern int msg_height;
    unsigned int new_width;
    unsigned int new_height;

    new_width = max_line_width + 2 * MSG_HPAD;
    new_height = number_of_lines * msg_height + 2 * MSG_VPAD;
    XResizeWindow(disp, TWL_window(wind), new_width, new_height);
  }

  /* map the window in case it's not mapped */
  XMapRaised(disp, TWL_window(wind));
  redraw_text_window(wind);

  free(save_str);
} /* write_text_window ends */

int redraw_text_window(TWIN wind)
     /* Redraws text window 'wind' using the message that is stored for it
        in the text window list; assumes that 'wind' has the correct size.
        If 'wind' is not on the list, no action is taken.

        Returns TRUE if 'wind' is on the list of text windows,
        FALSE otherwise */
     /* 6/3/96 - bug fix: accessed temp_str using indexing rather than
                 pointer increment so that it can be freed correctly */
{
  char*        temp_str;	/* used to store string, since
										XDrawString will insert nulls */
  unsigned int i;		/* index into temp_str */
  unsigned int begin_line;	/* index of first symbol on line containing
										temp_str[i] */
  const char* mesg_str;	/* string stored for this window */
  unsigned int current_line_length;
  unsigned int y_offset;

  mesg_str = TWL_message(wind);
  if (mesg_str == NULL) return FALSE;

  XClearWindow(disp, TWL_window(wind));

  /* create temporary string and store message in it */
  temp_str = malloc(1 + strlen(mesg_str));
  strcpy(temp_str, mesg_str);

  begin_line = 0;
  current_line_length = 0;
  y_offset = msg_yoffset + MSG_VPAD;
  for (i = 0; temp_str[i] != '\0'; i++) {
    /* INVARIANT: y_offset == msg_height * (number of '\n' so far) +
		 msg_yoffset
		 begin_line == index of character after most
		 recent '\n'
		 current_line_length == number of characters since most
		 recent '\n' */
    if (temp_str[i] == '\n') {
      XDrawString(disp, TWL_window(wind), msg_gc, MSG_HPAD, y_offset,
						&temp_str[begin_line], current_line_length);
      begin_line = i + 1;
      current_line_length = 0;
      y_offset += msg_height;
    }
    else current_line_length++;
  }

  if (current_line_length > 0) { /* unfinished line */
    XDrawString(disp, TWL_window(wind), msg_gc, MSG_HPAD, y_offset,
					 &temp_str[begin_line], current_line_length);
  }

  free(temp_str);

  XFlush(disp);
  return TRUE;
} /* redraw_text_window ends */

void hide_window(TWIN w)
{
  XUnmapWindow(disp, TWL_window(w));
} /* hide_window ends */

void kill_window(TWIN w)
{
  XDestroyWindow(disp, TWL_window(w));
  TWL_remove(w);
} /* kill_window ends */

void popup_message( int x, int y, char * message )
{
  char * appended_msg;			  /* message w/ prompt added */
  char * prompt = "Hit any key to continue.";
  TWIN text_window;
  XEvent pp_ev;

  appended_msg = (char *) malloc( strlen(message) + strlen(prompt) + 1 );
  strcpy( appended_msg, message );
  strcat( appended_msg, prompt );
  BEEP;
  text_window = create_text_window( x, y, appended_msg );
  /* wait for a keystroke */ 
  while ( TRUE ) {
    XNextEvent( disp, &pp_ev );
    if ( handle_background_event(pp_ev) ) continue;
    if ( pp_ev.type == KeyPress ) break;
	 else if ( pp_ev.type == Expose ) {
      if ( text_window == find_text_window( pp_ev.xexpose.window ) ) {
		  /* expose event for text window -> redraw it */
		  redraw_text_window( text_window );
      }
    }
    else
      BEEP;
  } /* while TRUE */

  kill_window( text_window );
  free( appended_msg );
}

/** end of Text.c **/

/*  [Last modified: 2007 06 28 at 19:31:52 GMT] */
